<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    * {
        margin: 0;
        padding: 0;
    }

    .contain {
        display: flex;

    }

    .left {
        width: 800px;
    }

    .head {
        width: 80%;
        height: 200px;
        background-color: green;

    }

    .bann {
        width: 80%;
        height: 400px;
        background-color: yellow;

    }

    .content {
        width: 80%;
        height: 1500px;
        background-color: red;

    }

    .s {
        margin-bottom: 10px;
    }

    .top {
        width: 100px;
        height: 100px;
        background-color: pink;
        top: 360px;
        position: absolute;
    }

    .goback {
        display: none;
    }
</style>

<body>
    <div class="contain">
        <div class="left">
            <div class="head s">
                头部区域
            </div>
            <div class="bann s">
                区域
            </div>
            <div class="content s">
                主体部分
            </div>
        </div>
        <div class="right">
            <div class="top">
                <span class='goback'>返回顶部</span>
            </div>
        </div>

    </div>


    <script>
        //封装函数解决兼容性问题
        //1、需要用到页面滚动事件scroll 因为是页面滚动，所以用到事件源是document
        //2、滚动到某一个位置就判断页面被卷进去的上部值
        //3、页面被卷去的头部可以通过window.pageYOffset获得，如果被卷去的左侧就用window.pageXOffset获得
        //4、注意：元素被卷去的头部是element.scrollTop,如果是页面被卷去的头部则是window.pageYOffset

        //5、当点击返回顶部得时候能够优雅得带有动画得返回顶部
        //（1）、此时可以用到我们封装好得动画函数
        //（2）、只需要把left的值改为垂直滚动的距离就可以
        //（3）、页面滚动了多少，可以通过window.pageYOffset得到
        //（4）、最后是页面滚动，使用window.scroll(x,y)来得到




        //对侧边栏进行操作，先获取侧边栏
        var slider = document.querySelector('.top');
        var ban = document.querySelector('.bann')
        var spa = document.querySelector('span')
        var content = document.querySelector('.content');
        var goback = document.querySelector('.goback')
        // console.log(ban.offsetTop); //这样可以获得bann容器到顶部的活的距离
        var bt = ban.offsetTop
        //解决侧边栏跳了一下后再固定的问题
        //需要先获得侧边栏到顶部的距离
        var sliderTop = slider.offsetTop - ban.offsetTop;

        //获取content到顶部的距离
        var contentTop = content.offsetTop;

        //注册点击事件:滚动事件
        document.addEventListener('scroll', function () {
            //window.pageYOffset:头部卷入的大小
            // console.log(window.parseInt(pageYOffset));
            //1、当banner到顶部的时候侧边栏固定
            if (window.parseInt(pageYOffset) >= bt) {
                slider.style.top = sliderTop + 'px'
                slider.style.position = 'fixed'
                spa.display = 'block'
            } else {
                slider.style.position = 'absolute'
                slider.style.top = 360 + 'px'
            }
            //2、当content到顶部的时候显示返回顶部的文字
            if (window.parseInt(pageYOffset) >= contentTop) {
                goback.style.display = 'block'
            } else {
                goback.style.display = 'none'
            }

        })
        //3、当点击返回顶部的时候返回顶部
        goback.addEventListener('click', function () {
            //因为是窗口滚动，所以对象是window
            animation(window, 0)
        })
        //4、引入缓动动画来实现点击返回顶部的时候，能够动画的缓慢的返回顶部，而不是一下子跳到顶部
        function animation(obj, target, callback) { //调用的时候用callback()
            clearInterval(obj.timer) //清除之前的定时器，只保留一个定时器
            obj.timer = setInterval(function () {
                //1、把步长值写道定时器中
                // var step = Math.ceil((target - obj.offsetLeft) / 10  )//向上取整
                //加一个判断，解决后退的时候能够准确到达位置
                var step = (target - window.pageYOffset) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step)
                //加个判断条件，让它停下来
                if (obj.offsetLeft == target) {
                    clearInterval(obj.timer)
                    //3、当定时器结束的时候判断这个回调函数有没有传进来，有的话就执行这个回调函数
                    // if(callback){
                    // callback()

                    // }
                    callback && callback() //等同于上面的代码  意思是当callback为真的话就执行callback()，否则不执行
                } else {
                    //2、每次加1  这个步长值改为一个慢慢变小的值
                    window.scroll(0,window.pageYOffset + step)
                }
            }, 30)
        }



    </script>
</body>

</html>